﻿using System;
using System.IO;
namespace Velocity4Net.Runtime.Logging
{
    /**
     * Logger used when no other is configured.  By default, all messages
     * will be printed to the System.err output stream.
     *
     * @author <a href="mailto:nbubna@apache.org">Nathan Bubna</a>
     * @version $Id: SystemLogChute.java 730039 2008-12-30 03:53:19Z byron $
     * @since 1.5
     */
    public class SystemLogChute : LogChute
    {
        public const String RUNTIME_LOG_LEVEL_KEY =
            "runtime.log.logsystem.system.level";
        public const String RUNTIME_LOG_SYSTEM_ERR_LEVEL_KEY =
            "runtime.log.logsystem.system.err.level";

        private int enabled = LogConstants.WARN_ID;
        private int errLevel = LogConstants.TRACE_ID;

        public void init(RuntimeServices rs)
        {
            // look for a level config property
            String level = (String)rs.getProperty(RUNTIME_LOG_LEVEL_KEY);
            if (level != null)
            {
                // and set it accordingly
                setEnabledLevel(toLevel(level));
            }

            // look for an errLevel config property
            String errLevel = (String)rs.getProperty(RUNTIME_LOG_SYSTEM_ERR_LEVEL_KEY);
            if (errLevel != null)
            {
                setSystemErrLevel(toLevel(errLevel));
            }
        }

        protected int toLevel(String level)
        {
            if (level.Equals("debug", StringComparison.OrdinalIgnoreCase))
            {
                return LogConstants.DEBUG_ID;
            }
            else if (level.Equals("info", StringComparison.OrdinalIgnoreCase))
            {
                return LogConstants.INFO_ID;
            }
            else if (level.Equals("warn", StringComparison.OrdinalIgnoreCase))
            {
                return LogConstants.WARN_ID;
            }
            else if (level.Equals("error", StringComparison.OrdinalIgnoreCase))
            {
                return LogConstants.ERROR_ID;
            }
            else
            {
                return LogConstants.TRACE_ID;
            }
        }

        protected String getPrefix(int level)
        {
            switch (level)
            {
                case LogConstants.WARN_ID:
                    return LogConstants.WARN_PREFIX;
                case LogConstants.DEBUG_ID:
                    return LogConstants.DEBUG_PREFIX;
                case LogConstants.TRACE_ID:
                    return LogConstants.TRACE_PREFIX;
                case LogConstants.ERROR_ID:
                    return LogConstants.ERROR_PREFIX;
                case LogConstants.INFO_ID:
                default:
                    return LogConstants.INFO_PREFIX;
            }
        }

        /**
         * Logs messages to either std.out or std.err
         * depending on their severity.
         *
         * @param level severity level
         * @param message complete error message
         */
        public void log(int level, String message)
        {
            // pass it off
            log(level, message, null);
        }

        /**
         * Logs messages to the system console so long as the specified level
         * is equal to or greater than the level this LogChute is enabled for.
         * If the level is equal to or greater than LogChute.ERROR_ID, 
         * messages will be printed to System.err. Otherwise, they will be 
         * printed to System.out. If a java.lang.Throwable accompanies the 
         * message, it's stack trace will be printed to the same stream
         * as the message.
         *
         * @param level severity level
         * @param message complete error message
         * @param t the java.lang.Throwable
         */
        public void log(int level, String message, System.Exception t)
        {
            if (!isLevelEnabled(level))
            {
                return;
            }

            String prefix = getPrefix(level);
            if (level >= this.errLevel)
            {
                write(Console.Error, prefix, message, t);
            }
            else
            {
                write(Console.Out, prefix, message, t);
            }
        }

        protected void write(TextWriter stream, String prefix, String message, System.Exception t)
        {
            stream.Write(prefix);
            stream.WriteLine(message);
            if (t != null)
            {
                stream.WriteLine(t);
                //t.printStackTrace(stream);
            }
        }

        /**
         * Set the minimum level at which messages will be printed.
         */
        public void setEnabledLevel(int level)
        {
            this.enabled = level;
        }

        /**
         * Returns the current minimum level at which messages will be printed.
         */
        public int getEnabledLevel()
        {
            return this.enabled;
        }

        /**
         * Set the minimum level at which messages will be printed to System.err
         * instead of System.out.
         */
        public void setSystemErrLevel(int level)
        {
            this.errLevel = level;
        }

        /**
         * Returns the current minimum level at which messages will be printed
         * to System.err instead of System.out.
         */
        public int getSystemErrLevel()
        {
            return this.errLevel;
        }

        /**
         * This will return true if the specified level
         * is equal to or higher than the level this
         * LogChute is enabled for.
         */
        public bool isLevelEnabled(int level)
        {
            return (level >= this.enabled);
        }

    }
}